﻿using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using XiAnAirport.BUS;
using XiAnAirport.BUS.Escalator;
using XiAnAirport.DAL;
using XiAnAirport.Models;

namespace XiAnAirport.ElevatorWebSocket
{
    public class ElevatorWebSocketMiddleware
    {
        public static ConcurrentDictionary<string, WebSocket> _sockets = new ConcurrentDictionary<string, WebSocket>();
        private readonly RequestDelegate _next;
        IWebSocketManage _manage;
        public static int AreaId;
        public static int IsAll;
        public static int Elevatorid;
        public static IWebSocketManage webSocketManage;
        //IWebSocketDataProc _dataProc;
        public static ConcurrentDictionary<int, ConcurrentDictionary<string, WebSocket>> _areasockets = new ConcurrentDictionary<int, ConcurrentDictionary<string, WebSocket>>();
        public static ConcurrentDictionary<int, ConcurrentDictionary<string, WebSocket>> _single_elevatorsockets = new ConcurrentDictionary<int, ConcurrentDictionary<string, WebSocket>>();
        private static ConcurrentDictionary<string, WebSocket> _elevatorlistsockets = new ConcurrentDictionary<string, WebSocket>();
        private static ConcurrentDictionary<string, WebSocket> _fault_reportsockets = new ConcurrentDictionary<string, WebSocket>();
        private static ConcurrentDictionary<string, WebSocket> homepagesockets = new ConcurrentDictionary<string, WebSocket>();
        private static ConcurrentDictionary<string, WebSocket> kone_homepagesockets = new ConcurrentDictionary<string, WebSocket>();
        private static ConcurrentDictionary<string, WebSocket> promptsockets = new ConcurrentDictionary<string, WebSocket>();
        private static ConcurrentDictionary<string, WebSocket> login_sockets = new ConcurrentDictionary<string, WebSocket>();
        public ElevatorWebSocketMiddleware(RequestDelegate next, IWebSocketManage manage)
        {
            this._next = next;
            this._manage = manage;
            this._manage.Socket = _sockets;
            this._manage.AreaSocket = _areasockets;
            this._manage.SingleElevatorSocket = _single_elevatorsockets;
            this._manage.ElevatorListSocket = _elevatorlistsockets;
            this._manage.FaultReportSocket = _fault_reportsockets;
            this._manage.HomePageSocket = homepagesockets;
            this._manage.KoneHomePageSocket = kone_homepagesockets;
            this._manage.PromptSockets = promptsockets;
            this._manage.LoginSockets = login_sockets;
            webSocketManage = _manage;
            // this._dataProc = dataProc;
        }
        public async Task Invoke(HttpContext context)
        {
            try
            {
                if (!context.WebSockets.IsWebSocketRequest)
                {
                    await _next.Invoke(context);
                    return;
                }
                CancellationToken cancellationToken = context.RequestAborted;
                var currentSocket = await context.WebSockets.AcceptWebSocketAsync();
                string socketId = context.Request.Query["sid"];


                #region area字典

                if (socketId == "1")
                {
                    string loginname = context.Request.Query["loginname"];
                    int areaid = int.Parse(context.Request.Query["areaid"]);
                    ConcurrentDictionary<string, WebSocket> area = new ConcurrentDictionary<string, WebSocket>();
                    ConcurrentDictionary<string, WebSocket> areatemp = new ConcurrentDictionary<string, WebSocket>();
                    foreach (var kep in _areasockets)
                    {
                        if (kep.Value.ContainsKey(loginname))
                        {
                            WebSocket socket;
                            kep.Value.Remove(loginname, out socket);
                        }
                    }
                    _areasockets.TryGetValue(areaid, out area);
                    if (area != null)
                    {
                        areatemp = area;
                        areatemp.TryAdd(loginname, currentSocket);
                    }
                    else
                    {
                        areatemp.TryAdd(loginname, currentSocket);
                    }

                    _areasockets.TryAdd(areaid, areatemp);
                }
                else if (socketId == "2")
                {
                    string loginname = context.Request.Query["loginname"];
                    if (_fault_reportsockets.ContainsKey(loginname))
                    {
                        WebSocket socket;
                        _fault_reportsockets.Remove(loginname, out socket);
                    }
                    _fault_reportsockets.TryAdd(loginname, currentSocket);
                }
                else if (socketId == "3")
                {
                    string loginname = context.Request.Query["loginname"];
                    int elevatorid = int.Parse(context.Request.Query["elevatorid"]);
                    ConcurrentDictionary<string, WebSocket> elevatorsingle = new ConcurrentDictionary<string, WebSocket>();
                    ConcurrentDictionary<string, WebSocket> elevatorsingletemp = new ConcurrentDictionary<string, WebSocket>();
                    foreach (var kep in _single_elevatorsockets)
                    {
                        if (kep.Value.ContainsKey(loginname))
                        {
                            WebSocket socket;
                            kep.Value.Remove(loginname, out socket);
                        }
                    }
                    _single_elevatorsockets.TryGetValue(elevatorid, out elevatorsingle);
                    if (elevatorsingle != null)
                    {
                        elevatorsingletemp = elevatorsingle;
                        elevatorsingletemp.TryAdd(loginname, currentSocket);
                    }
                    else
                    {
                        elevatorsingletemp.TryAdd(loginname, currentSocket);
                    }
                    _single_elevatorsockets.TryAdd(elevatorid, elevatorsingletemp);
                }
                else if (socketId == "4")
                {
                    string loginname = context.Request.Query["loginname"];
                    if (_elevatorlistsockets.ContainsKey(loginname))
                    {
                        WebSocket socket;
                        _elevatorlistsockets.Remove(loginname, out socket);
                    }
                    _elevatorlistsockets.TryAdd(loginname, currentSocket);
                }
                else if (socketId == "5")
                {
                    string loginname = context.Request.Query["loginname"];
                    if (homepagesockets.ContainsKey(loginname))
                    {
                        WebSocket socket;
                        homepagesockets.Remove(loginname, out socket);
                    }
                    homepagesockets.TryAdd(loginname, currentSocket);
                }
                else if (socketId == "6")
                {
                    string loginname = context.Request.Query["loginname"];
                    if (kone_homepagesockets.ContainsKey(loginname))
                    {
                        WebSocket socket;
                        kone_homepagesockets.Remove(loginname, out socket);
                    }
                    kone_homepagesockets.TryAdd(loginname, currentSocket);
                }
                else if (socketId == "7")
                {
                    string loginname = context.Request.Query["loginname"];
                    if (promptsockets.ContainsKey(loginname))
                    {
                        WebSocket socket;
                        promptsockets.Remove(loginname, out socket);
                    }
                    promptsockets.TryAdd(loginname, currentSocket);
                }
                else if (socketId == "8")
                {
                    string loginname = context.Request.Query["loginname"];
                    if (loginname != "undefined")
                    {
                        if (login_sockets.ContainsKey(loginname))
                        {
                            PushLoginMessage(loginname, "exit");

                            WebSocket socket;
                            login_sockets.Remove(loginname, out socket);
                        }
                        login_sockets.TryAdd(loginname, currentSocket);
                    }
                }
                else if (socketId == "9")
                {
                    string deviceno = context.Request.Query["DeviceNo"];
                    int ChannelIndex = Convert.ToInt32(context.Request.Query["ChannelIndex"]);
                    string device_sn = context.Request.Query["DeviceSN"];
                    if (!string.IsNullOrEmpty(deviceno) && ChannelIndex > -1)
                    {
                        ElevatorAreaDAL elevatorAreaDAL = new ElevatorAreaDAL();
                        Elevator elevator = elevatorAreaDAL.LoadElevatorByNo(deviceno);
                        if (elevator != null)
                        {
                            int index = EscalatorBUS.list.FindIndex(x => x.DecviceNo == deviceno && x.ChannelIndex == ChannelIndex && x.DeviceSN==device_sn);
                            if (index > -1)
                            {
                                EscalatorBUS.list[index].socket = currentSocket;
                            }
                            else
                            {
                                EscalatorInfo escalatorInfo = new EscalatorInfo();
                                escalatorInfo.DeviceIP = elevator.ipAddress;
                                escalatorInfo.DecviceNo = deviceno;
                                escalatorInfo.ChannelIndex = ChannelIndex;
                                escalatorInfo.DeviceSN = device_sn;
                                escalatorInfo.socket = currentSocket;
                                EscalatorBUS.list.Add(escalatorInfo);
                            }

                            EscalatorSocket escalatorSocket = new EscalatorSocket();
                            escalatorSocket.deviceip = elevator.ipAddress;
                            escalatorSocket.deviceno = deviceno;
                            escalatorSocket.ChannelIndex = ChannelIndex;
                            escalatorSocket.device_sn = device_sn;
                            await escalatorSocket.ConnectServer(string.Format("ws://{0}?ChannelIndex={1}&DeviceSN={2}", elevator.ipAddress, ChannelIndex,device_sn));
                            EscalatorBUS.device_list.Add(escalatorSocket);
                        }
                    }
                }


                #endregion

                while (!currentSocket.CloseStatus.HasValue)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }
                    string response = await ReceiveStringAsync(currentSocket, cancellationToken);
                    if (response != null)
                    {
                        System.Diagnostics.Debug.Write($"Websocket-Recevices:{response}");
                        if (socketId == "1")
                        {
                            string[] a = response.Split(",");
                            AreaId = int.Parse(a[0]);
                            IsAll = int.Parse(a[1]);
                        }
                        else if (socketId == "3")
                        {
                            Elevatorid = int.Parse(response);
                        }
                    }
                }
                if (currentSocket != null && currentSocket.CloseStatus != null)
                {
                    await currentSocket.CloseAsync(currentSocket.CloseStatus.Value, currentSocket.CloseStatusDescription, CancellationToken.None);
                    List<EscalatorInfo> escalatorInfos = EscalatorBUS.list.FindAll(x => x.socket == currentSocket);
                    if (escalatorInfos != null && escalatorInfos.Count > 0)
                    {
                        EscalatorBUS.list.RemoveAll(x => x.socket == currentSocket);
                        foreach (var item in escalatorInfos)
                        {
                            int index = EscalatorBUS.device_list.FindIndex(x => x.deviceip == item.DeviceIP && x.ChannelIndex == item.ChannelIndex && x.device_sn==item.DeviceSN);
                            if (index > -1)
                            {
                                EscalatorSocket escalatorSocket = EscalatorBUS.device_list[index];
                                await escalatorSocket.CloseServer();
                            }
                        }
                    }

                }

            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Write($"Websocket-Error:{e.ToString()}");
            }
        }

        public static async Task<bool> PushLoginMessage(string name, string message)
        {
            return await ElevatorWebSocketMiddleware.webSocketManage.PushLoginMessage(name, message);
        }

        public static async Task<string> ReceiveStringAsync(WebSocket socket, CancellationToken ct)
        {
            var buffer = new ArraySegment<byte>(new byte[4 * 1024]);
            using (var ms = new MemoryStream())
            {
                WebSocketReceiveResult result;
                do
                {
                    ct.ThrowIfCancellationRequested();
                    try
                    {
                        result = await socket.ReceiveAsync(buffer, ct);
                        ms.Write(buffer.Array, buffer.Offset, result.Count);
                    }
                    catch (Exception e) { return null; }
                }
                while (!result.EndOfMessage);
                ms.Seek(0, SeekOrigin.Begin);
                if (result.MessageType != WebSocketMessageType.Text)
                {
                    return null;
                }
                using (var reader = new StreamReader(ms, Encoding.UTF8))
                {
                    return await reader.ReadToEndAsync();
                }
            }
        }

    }
}
